import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'

/***
 * UI组件创建声明标识符使用大驼峰命名法，
 * 普通的变量和函数使用小驼峰命名法。
 */
function App() {
  const [count, setCount] = useState(0)
  return (
    <>
      <div>
        <a href="https://vitejs.dev" target="_blank">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <h1>🤡宇宙最强网站!</h1>
      <div className="card">
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
        <p>
          Edit <code>src/App.jsx</code> and save to test HMR
        </p>
      </div>
      <p className="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
      {/* <ErnieAiApp /> 注释语法:用大括号使用js的多行注释...*/}
      <ErnieAiApp />
    </>
  )
}

function ErnieAiApp() {
  return (
    <div id="ErnieAiAppId">
      <h1 id="ErnieAiAppH1">ERNIE AI APP</h1>
      <ErnieAiAppTest1 
        ernieAiAppTest1Name = "ernieAiAppTest1Name"
        ernieAiAppTest1Number = {0}
      /> 
      <ErnieAiAppChild1 
        name = "ErnieAiAppChild1"
      />
      <ErnieAiAppChild2 
        name = "ErnieAiAppChild2"
      />
    </div>
  )
}
let ernieAiAppReturn = ErnieAiApp()
console.log(ernieAiAppReturn)

// state:
// 组件的初始化过程和状态更新机制
// 状态变量(state variable)是state对象的具体属性或值。
// setXxx方法修改state(对象,引用类型)的state变量的值。
// state变量初始值(当前值)通过返回的数组通过解构赋值给了程序员自己声明的变量而已(但这个变量称为state变量...)。
// 每个Fiber节点有一个链表，state存储在hooks链表中，
// 
// 第一次渲染时，使用组件时会调用组件函数(使用组件非直接调用组件函数),
// 组件函数会调用组件的钩子(前提是组件里有...)例如useState,
// state储存在Fiber节点的hooks链表中,
// useState会判断Fiber树当前节点的hooks链表是否为空链表,为空链表即还没有进行第一次渲染。
//let componentRenderCount = 0
function ErnieAiAppTest1({ernieAiAppTest1Name, ernieAiAppTest1Number}) {
//function ErnieAiAppTest1(props) {
  //console.log("<---------- component function start: ", "componentRenderCount=", ++componentRenderCount, "---------->" )
  //console.log("props: ", props)
  //const propsPrototype = Object.getPrototypeOf(props)
  //console.log("props's prototype:  ", propsPrototype, typeof propsPrototype)
  const result = useState(0)
  const [count,] = result
  const [,setCount] = result
  //console.log(count, typeof count)
  function handleClickIncrease() {
    //在回调函数中传入count
    setCount((countArg) => {
      //console.log("countArg=", countArg)
      return ++countArg
    })
  }
  function handleClickReduce() {
    setCount((countArg) => {
      //console.log("countArg=", countArg)
      return --countArg
    })
  }
  function handleClickReset() {
    setCount(0)
  }
  //console.log("count=", count)
  //console.log("<----------- component function end: ", "componentRenderCount=", componentRenderCount, "----------->" )
  return (
    // JSX语法，会被编译成JS原生代码。
    <div>
      <h1>Ernie Ai Test1</h1>
      {/*<h2 id="fyf">{props.ernieAiAppTest1Name}</h2>*/}
      <h2 id="fyf">{ernieAiAppTest1Name}{ernieAiAppTest1Number}</h2>
      <h2>计数器：{count}</h2>
      <button onClick={handleClickIncrease}>自增</button>
      <button onClick={handleClickReduce}>自减</button>
      <button onClick={handleClickReset}>重置</button>
    </div>
  )
}

/*
  对象解构：
  对象解构就是使用与对象匹配的结构来实现对对象属性赋值.
  这里的结构指的是语法形式。
  1.变量直接使用属性名;(简写语法)
  2.在类似对象字面量的结构中,声明多个变量,同时执行多个赋值操作;
  个人表述:在与对象相匹配的结构中,声明变量,同时执行赋值操作.
  解构表达式：目标对象=源对象
  给已经声明的变量赋值,解构表达式要用圆括号括起来.
*/
function ErnieAiAppChild1({name}) {
  return (
    <h1>{name}</h1>
  )
}

function ErnieAiAppChild2({name: componentName}) {
  return (
    <h1>{componentName}</h1>
  )
}

// id为fyf的节点，包含多个text节点？
//setTimeout(() => {
//  let selectedNode = document.getElementById("fyf")
//  console.log(selectedNode)
//// 放入宏任务队列，作用是等待页面的DOM渲染完成。
//}, 100)

export default App

/**
 * 快速入门 笔记:
 *
 * 渲染模板是指将实际的数据填入到模板(静态HTML结构)中定义好的占位符或表达式的过程。
 * 
 * HTML (HyperText Markup Language) 
 * html markup tags
 * UI (user interface)
 * building blocks 构建块
 * React app由组件(components)组成。
 * 一个组件是一块拥有自己的逻辑和外观的用户界面(UI);
 * 组件：UI构建块(UI building blocks)
 * React组件是返回markup(标记)的JS函数。
 * 注意：开发时用JSX语法声明组件函数，在编译时会被转译成相应的JS原生代码。
 * component function 组件函数
 * React组件非“传统”模板，Render组件(component)
 * 
 * JSX标签语法中,标签中大括号内可使用javscript表达式。
 * React在渲染过程中，把UI组件树转换成对应的virtual DOM树，
 * virtual DOM --> Fiber树(+hooks链表) --> DOM
 * 通过virtual DOM最终更新到真实的DOM中。
 * 
 * 事件属性 -> 事件处理函数
 * 
 * 注意：使用Hook这个要细看官方文档，不遵守Hook的规则，会出现难以发现的隐藏错误，
 * 即使运行时看起来“正常”。(是什么原因待以后深究...老子现在还没入门...)
 * 个人目前理解：hooks与UI组件“一一顺序对应”，在if或for,while等代码块在调用
 * useXXX这些函数时，会出现"扰乱"顺序的情况，从而导致出现隐蔽的错误。
 * 非权威解释，待以后验证并修改补充或删除错误。
 * 正式解释：Fiber树节点的hooks链表存储state对象,useState顺序是按hooks链表的顺序来调用的,
 * if或for,while语句会出现代码块内的useState不执行的情况,和useState的调用顺序对不上。
 * 
 * 定义组件：
 * React组件是能通过标记(embed)嵌入/sprinkle(撒落、点缀、零星分布)到JS函数。
 * 具体指的是return后的html-like标记为所谓的嵌入到JS函数(JSX语法)
 *
 * 官方文档两个提到React组件的定义个人合并总结:
 *  React组件是返回标记(markup:包括tags<标签>和content(内容))的JS函数,这些JS函数可以通过标记(markup)嵌入。
 *  React组件必须以大写字母开头。
 *  组件的定义不要嵌套。JS解释器会重新解释被嵌套的组件定义代码，然而这是没有必要的，影响性能。(且可能会有bug?)
 *
 * 在React中,渲染逻辑和标记共同存在于同一个地方——组件
 *
 * 
 * 使用React组件:定义组件后，可以把组件嵌套在其它组件内。
 * 使用React组件的本质:
 * const element = <Greeting name="John" />;
 * 嵌套(nesting)组件((sprinkle:撒落、点缀、零星分布)嵌入Greeting[必须大写字母开头]标签)
 * 嵌入标签的目的是使用组件。
 *    会被编译成
 * const element = React.createElement(Greeting, { name: 'John' });
 * 这个例子展示了JSX语法中React(使用)组件的本质。
 * JSX标签中{}内使用React组件，会被编译成React.createElement()
 * 通过virtual DOM树，最终更新到真实的DOM中，实现渲染的过程,
 * 因此不是在HTML中插入<script>标签来写入js代码。
 * 
 * UI树(组件树,虚拟DOM树),想象一下树数据结构的遍历方式。递归
 * 
 * JSX语法参考组件声明函数里return返回的标记.
 *
 *
 * 组件间通信,"状态提升",state移到父组件,通过props把state变量和setState的方法传递到子组件。
 * 在子组件setState后,父组件的state变量被修改,父组件再次通过props将修改后的state变量传入子组件,
 * 子组件也会被重新渲染。
 * 
 */

/*
 * 描述UI：
 *
 *  第一个组件
 *    ...
 *
 *  组件的导入与导出
 *    默认导出:
 *     import后可任意命名
 *    命名导出
 *    ...
 *
 *  使用JSX写标记语言
 *    ...
 *
 *    JSX规则：
 *     1.返回单一根元素(root element:元素=标签+内容)
 *       为了从一个组件返回多个元素，用一个父标签把它们包装/包裹(wrapping)起来。
 *       空标签叫做fragment(片段;分段),<></>
 *       Fragments可以让你分组元素而不在浏览器HTML树留下任何痕迹。
 *       React.elelment的type为Symbol(react.fragment),不会在DOM中出现.
 *       组件设计成返回单一元素,是为了组件树的一致性.
 *
 *       因为JS函数只能返回一个对象,只能通过把多个对象包装在数组里才能返回多个对象.
 *
 *    2.闭合所有标签
 *      self-closing tags 自闭合标签 <img>,JSX语法中,为<img />;
 *      wrapping tags 包装标签，包裹/包装标签 <li>xxx</li>;
 *      self-closing tag 
 *
 *    3.使用驼峰式命名法给属性命名
 *      JSX最终会被转译成javascript,js的变量名命名是有命名限制规则的，
 *      个人胡乱理解,待修正完善...：
 *      React.element() --> 虚拟DOM元素对象{React.elelment} --> 对象解构赋值直接使用对象属性名可简写 -->
 *      JSX语法中括号内{}使用js表达式,表达式内包括解构赋值传进来的虚拟DOM元素属性同名变量,因此该变量需要
 *      符合JS变量命名规则,且React中大部分属性使用驼峰命名法,驼峰命名符合js变量命名规范。
 *
 *      组件-->JSX-->JS对象-->对象解构简写语法-->子组件JSX{}大括号内使用js表达式.(变量名要符合js语法)
 *    
 *
 * 在JSX中通过大括号使用JavaScript
 *   使用引号传递字符串
 *  ...
 *
 *
 */

/*
 * JSX中实现注释的方法：本质是使用{}以使用javascript表达式的方式来"间接"实现注释。
 *
 * JSX要先转译成JS原生代码，JS解释器才能执行。
 * 举例，下面的JSX代码，转译后的JS原生代码return后也是是没有圆括号的,
 * JS解释器可能会(ASI,automatic semicolon insertion)自动在return后插入一个分号。
 * 
 */

